﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace UBCon.Ribbon
{
    internal partial class RibbonTabItemPanel
    {
        #region IScrollInfo Implementaion

        /// <summary>
        /// 
        /// </summary>
        [DefaultValue(false)]
        public bool CanHorizontallyScroll
        {
            get
            {
                return this.canHScroll;
            }
            set
            {
                this.canHScroll = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        [DefaultValue(false)]
        public bool CanVerticallyScroll
        {
            get
            {
                return this.canVScroll;
            }
            set
            {
                this.canVScroll = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public double ExtentHeight
        {
            get { return this._extent.Height; }
            set { this._extent.Height = value; }
        }

        public double ExtentWidth
        {
            get { return this._extent.Width; }
            set { this._extent.Width = value; }
        }

        public double HorizontalOffset
        {
            get { return this.offset.X; }
            set { this.offset.X = value; }
        }

        public double VerticalOffset
        {
            get { return this.offset.Y; }
            set { this.offset.Y = value; }
        }

        public double ViewportHeight
        {
            get { return this._viewport.Height; }
            set { this._viewport.Height = value; }
        }

        public double ViewportWidth
        {
            get { return this._viewport.Width; }
            set { this._viewport.Width = value; }
        }
        public void LineDown()
        {
            this.SetVerticalOffset(this.VerticalOffset + this.ScrollBy);
        }

        public void LineLeft()
        {
            this.SetHorizontalOffset(this.HorizontalOffset - this.ScrollBy);
        }

        public void LineRight()
        {
            this.SetHorizontalOffset(this.HorizontalOffset + this.ScrollBy);
        }

        public void LineUp()
        {
            this.SetVerticalOffset(this.VerticalOffset - this.ScrollBy);
        }

        public System.Windows.Rect MakeVisible(System.Windows.Media.Visual visual, System.Windows.Rect rectangle)
        {
            if (rectangle.IsEmpty || visual == null || visual == this || !base.IsAncestorOf(visual))
            {
                return System.Windows.Rect.Empty;
            }
            rectangle = visual.TransformToVisual(this).TransformBounds(rectangle);
            System.Windows.Rect viewRect = new System.Windows.Rect(this.HorizontalOffset, this.VerticalOffset, this.ViewportWidth, this.ViewportHeight);
            rectangle.X += viewRect.X;
            rectangle.Y += viewRect.Y;
            viewRect.X = this.CalculateNewScrollOffset(viewRect.Left, viewRect.Right, rectangle.Left, rectangle.Right);
            viewRect.Y = this.CalculateNewScrollOffset(viewRect.Top, viewRect.Bottom, rectangle.Top, rectangle.Bottom);
            this.SetHorizontalOffset(viewRect.X);
            this.SetVerticalOffset(viewRect.Y);
            rectangle.Intersect(viewRect);
            rectangle.X -= viewRect.X;
            rectangle.Y -= viewRect.Y;
            return rectangle;
        }


        public void MouseWheelDown()
        {
            this.SetVerticalOffset(this.VerticalOffset + this.ScrollBy);
        }

        public void MouseWheelLeft()
        {
            this.SetHorizontalOffset(this.HorizontalOffset - this.ScrollBy);
        }

        public void MouseWheelRight()
        {
            this.SetHorizontalOffset(this.HorizontalOffset + this.ScrollBy);
        }

        public void MouseWheelUp()
        {
            this.SetVerticalOffset(this.VerticalOffset - this.ScrollBy);
        }

        public void PageDown()
        {
            this.SetVerticalOffset(this.VerticalOffset + this.ViewportHeight);
        }

        public void PageLeft()
        {
            this.SetHorizontalOffset(this.HorizontalOffset - this.ViewportWidth);
        }

        public void PageRight()
        {
            this.SetHorizontalOffset(this.HorizontalOffset + this.ViewportWidth);
        }

        public void PageUp()
        {
            this.SetVerticalOffset(this.VerticalOffset - this.ViewportHeight);
        }

        public System.Windows.Controls.ScrollViewer ScrollOwner
        {
            get
            {
                return scrollViewer;
            }
            set
            {
                scrollViewer = value;
               
            }
        }

        public void SetHorizontalOffset(double offset)
        {
            offset = this.ValidateHorizontalOffset(offset);
            if (!MS.Internal.DoubleUtil.AreClose(offset, this.offset.X))
            {
                this.offset.X = offset;

                if (this.ScrollOwner != null)
                {
                    this.ScrollOwner.InvalidateScrollInfo();
                    this.Scroll(this.HorizontalOffset, this.VerticalOffset);

                }
            }
        }

        public void SetVerticalOffset(double offset)
        {
            offset = this.ValidateVerticalOffset(offset);
            if (!MS.Internal.DoubleUtil.AreClose(offset, this.offset.Y))
            {
                this.offset.Y = offset;
                if (this.ScrollOwner != null)
                {
                    this.ScrollOwner.InvalidateScrollInfo();
                    this.Scroll(this.HorizontalOffset, this.VerticalOffset);
                }
            }
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        internal double ValidateHorizontalOffset(double offset)
        {
            //RibbonScrollViewer scroller = this.ScrollOwner as RibbonScrollViewer;
            if (this.ViewportWidth >= ExtentWidth)
            {
                if (ScrollOwner != null) 
                {
                    ScrollOwner.SetValue(ScrollViewerHelper.CanLineLeftProperty, false);
                    ScrollOwner.SetValue(ScrollViewerHelper.CanLineRightProperty, false);
                }
                return 0;
            }
            if (offset <= 1)
            {
                offset = 0;
                if (ScrollOwner != null)
                {
                    ScrollOwner.SetValue(ScrollViewerHelper.CanLineLeftProperty, false);
                    ScrollOwner.SetValue(ScrollViewerHelper.CanLineRightProperty, true);
                }
            }
            else
            {
                if (offset + 1 >= ExtentWidth - ViewportWidth)
                {
                    offset = ExtentWidth - ViewportWidth;
                    if (ScrollOwner != null)
                    {
                        ScrollOwner.SetValue(ScrollViewerHelper.CanLineLeftProperty, true);
                        ScrollOwner.SetValue(ScrollViewerHelper.CanLineRightProperty, false);
                    }
                }
                else
                {
                    if (ScrollOwner != null)
                    {
                        ScrollOwner.SetValue(ScrollViewerHelper.CanLineLeftProperty, true);
                        ScrollOwner.SetValue(ScrollViewerHelper.CanLineRightProperty, true);
                    }
                }

            }
            return offset;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        internal double ValidateVerticalOffset(double offset)
        {
           // RibbonScrollViewer scroller = this.ScrollOwner as RibbonScrollViewer;
            if (this.ViewportHeight >= ExtentHeight)
            {
                if (ScrollOwner != null) 
                {
                    ScrollOwner.SetValue(ScrollViewerHelper.CanLineUpProperty, false);
                    ScrollOwner.SetValue(ScrollViewerHelper.CanLineDownProperty, false);
                } 
                
                return 0;
            }
           
            if (offset <= 1)
            {
                offset = 0;
                if (ScrollOwner != null)
                {
                    ScrollOwner.SetValue(ScrollViewerHelper.CanLineUpProperty, false);
                    ScrollOwner.SetValue(ScrollViewerHelper.CanLineDownProperty, true);
                }
            }
            else
            {
                if (this.ExtentHeight - ViewportHeight - offset <= 3)
                {
                    offset = ExtentHeight - ViewportHeight;
                    if (ScrollOwner != null)
                    {
                        ScrollOwner.SetValue(ScrollViewerHelper.CanLineUpProperty, true);
                        ScrollOwner.SetValue(ScrollViewerHelper.CanLineDownProperty, false);
                    }
                }
                else
                {
                    if (ScrollOwner != null)
                    {
                        ScrollOwner.SetValue(ScrollViewerHelper.CanLineUpProperty, true);
                        ScrollOwner.SetValue(ScrollViewerHelper.CanLineDownProperty, true);
                    }
                }
            }
            return offset;
        }

        Storyboard TransfromAnimation = null;
        DoubleAnimation anim = null;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="xOffset"></param>
        /// <param name="yOffset"></param>
        private void Scroll(double xOffset, double yOffset)
        {
            if (this.AnimatedScroll)
            {
                if (this.TransfromAnimation == null)
                {
                    TransfromAnimation = new Storyboard();
                    anim = new DoubleAnimation();
                    anim.Duration = new Duration(System.TimeSpan.FromMilliseconds(300));
                    TransfromAnimation.Children.Add(anim);
                }
                if (Orientation == System.Windows.Controls.Orientation.Horizontal)
                {
                    Storyboard.SetTargetProperty(anim, new PropertyPath("(0).(1)", RenderTransformProperty, TranslateTransform.XProperty));
                    anim.To = (-1) * xOffset;
                }
                else
                {
                    Storyboard.SetTargetProperty(anim, new PropertyPath("(0).(1)", RenderTransformProperty, TranslateTransform.YProperty));
                    anim.To = (-1) * yOffset;
                }
                
                EventHandler handler = null;
                handler = delegate
                {
                    TransfromAnimation.Completed -= handler;
                    _translate.X = (-1) * xOffset;
                    _translate.Y = (-1) * yOffset;
                    InvalidateMeasure();

                };
                TransfromAnimation.Completed += handler;
                TransfromAnimation.Begin(this, true);
            }
            else
            {
                _translate.X = -xOffset;
                _translate.Y = -yOffset;
                InvalidateMeasure();

            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="size"></param>
        internal void UpdateScrollInfo(System.Windows.Size size)
        {
            bool extentChanged = false, viewportChanged = false;
            double extent = CalculateExtent();
            if (Orientation == System.Windows.Controls.Orientation.Horizontal)
            {
                if (_extent.Width != extent)
                {
                    _extent.Width = extent;
                    extentChanged = true;
                }
                if (_viewport.Width != size.Width)
                {
                    _viewport.Width = size.Width;
                    viewportChanged = true;
                }

            }
            else
            {
                if (_extent.Height != extent)
                {
                    _extent.Height = extent;
                    extentChanged = true;
                }
                if (_viewport.Height != size.Height)
                {
                    _viewport.Height = size.Height;
                    viewportChanged = true;
                }

            }

            if ((extentChanged || viewportChanged) && this.ScrollOwner != null)
            {
                offset.X = ValidateHorizontalOffset(offset.X);
                offset.Y = ValidateVerticalOffset(offset.Y);
                ScrollOwner.InvalidateScrollInfo();
                Scroll(HorizontalOffset, VerticalOffset);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private double CalculateExtent()
        {
            double size = 0;
            if (this.Orientation == System.Windows.Controls.Orientation.Horizontal)
            {
                foreach (System.Windows.UIElement item in InternalChildren)
                {
                    size += item.DesiredSize.Width;
                }
            }
            else
            {
                foreach (System.Windows.UIElement item in InternalChildren)
                {
                    size += item.DesiredSize.Height;
                }
            }
            return size;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="offset"></param>
        internal void ScrollWithoutAnimation(double offset)
        {
            offset = this.ValidateVerticalOffset(offset);
            this.offset.Y = offset;
            if (this.ScrollOwner != null)
            {
                this.ScrollOwner.InvalidateScrollInfo();
                this._translate.Y = -offset;
                this.InvalidateMeasure();
            }

        }

        private double CalculateNewScrollOffset(double topView, double bottomView, double topChild, double bottomChild)
        {
            bool offBottom = topChild < topView && bottomChild < bottomView;
            bool offTop = bottomChild > bottomView && topChild > topView;
            bool tooLarge = (bottomChild - topChild) > (bottomView - topView);

            if (!offBottom && !offTop)
            { return topView; } //Don't do anything, already in view

            if ((offBottom && !tooLarge) || (offTop && tooLarge))
            { return topChild; }

            return (bottomChild - (bottomView - topView));
        }
    }
}
